package com.gitee.apanlh.util.algorithm;

import com.gitee.apanlh.exp.algorithm.InitPrivateKeyException;
import com.gitee.apanlh.exp.algorithm.InitPublicKeyException;
import com.gitee.apanlh.util.encode.Base64Utils;
import com.gitee.apanlh.util.encode.HexUtils;
import com.gitee.apanlh.util.random.RandomUtils;
import com.gitee.apanlh.util.valid.ValidParam;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil;
import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.crypto.util.PrivateKeyInfoFactory;
import org.bouncycastle.crypto.util.PublicKeyFactory;
import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.bouncycastle.math.ec.ECPoint;

import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.PublicKey;

/**
 * 	EC密钥相关工具类
 * 	
 * 	@author Pan
 */
public class ECKeyUtils {
	
	/**
	 * 	默认构造函数
	 * 	
	 * 	@author Pan
	 */
	private ECKeyUtils() {
		// 不允许外部构造
		super();
	}
	
	/**
	 * 	生成EC密钥对
	 * 	
	 * 	@author Pan
	 * 	@param 	parameters	椭圆曲线参数
	 * 	@return	AsymmetricCipherKeyPair
	 */
	public static AsymmetricCipherKeyPair generateKeyPair(ECDomainParameters parameters) {
		ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
		keyPairGenerator.init(new ECKeyGenerationParameters(parameters, RandomUtils.getRandomOfSecure()));
		return keyPairGenerator.generateKeyPair();
	}
	
	/**	
	 * 	生成公钥
	 * 	
	 * 	@author Pan
	 * 	@param 	key			公钥
	 * 	@param 	parameters	椭圆曲线参数
	 * 	@return	ECPublicKeyParameters
	 */
	public static ECPublicKeyParameters generatePublicKey(AsymmetricKeyParameter key, ECDomainParameters parameters) {
		return new ECPublicKeyParameters(((ECPublicKeyParameters) key).getQ(), parameters);
	}

	/**	
	 * 	生成公钥
	 * 	
	 * 	@author Pan
	 * 	@param 	key			公钥
	 * 	@param 	parameters	椭圆曲线参数
	 * 	@return	ECPublicKeyParameters
	 */
	public static ECPublicKeyParameters generatePublicKey(ECPoint key, ECDomainParameters parameters) {
		return new ECPublicKeyParameters(key, parameters);
	}
	
	/**	
	 * 	生成公钥
	 * 	
	 * 	@author Pan
	 * 	@param 	keyPair		密钥对
	 * 	@param 	parameters	椭圆曲线参数
	 * 	@return	ECPublicKeyParameters
	 */
	public static ECPublicKeyParameters generatePublicKey(AsymmetricCipherKeyPair keyPair, ECDomainParameters parameters) {
		return generatePublicKey(keyPair.getPublic(), parameters);
	}
	
	/**	
	 * 	生成公钥
	 * 	<br>支持Q值(默认方式)
	 * 	<br>X.509方式
	 * 	
	 * 	@author Pan
	 * 	@param 	publicKey	公钥
	 * 	@param 	parameters	椭圆曲线参数
	 * 	@return	ECPublicKeyParameters
	 */
	public static ECPublicKeyParameters generatePublicKey(byte[] publicKey, ECDomainParameters parameters) {
		try {
			//	默认Q值解析
			if (ValidParam.isNotNull(parameters)) {
				return new ECPublicKeyParameters(parameters.getCurve().decodePoint(publicKey), parameters);
			}
		} catch (Exception e) {
			//	do nothing
		}
		
		//	X.509解析
		try {
			SubjectPublicKeyInfo instance = SubjectPublicKeyInfo.getInstance(publicKey);
			return (ECPublicKeyParameters) PublicKeyFactory.createKey(instance);
		} catch (Exception e) {
			try {
				//	OpenSSH解析
				return (ECPublicKeyParameters) OpenSSHPublicKeyUtil.parsePublicKey(publicKey);
			} catch (Exception e2) {
				throw new InitPublicKeyException(e2.getMessage(), e2);
			}
		}
	}
	
	/**	
	 * 	生成公钥
	 * 	
	 * 	@author Pan
	 * 	@param 	publicKey	公钥
	 * 	@return	ECPublicKeyParameters
	 */
	public static ECPublicKeyParameters generatePublicKey(PublicKey publicKey) {
		try {
			return (ECPublicKeyParameters) ECUtil.generatePublicKeyParameter(publicKey);
		} catch (Exception e) {
			throw new InitPublicKeyException(e.getMessage(), e);
		}
	}
	
	/**	
	 * 	生成私钥
	 * 	
	 * 	@author Pan
	 * 	@param 	key			私钥
	 * 	@param 	parameters	椭圆曲线参数
	 * 	@return	ECPrivateKeyParameters
	 */
	public static ECPrivateKeyParameters generatePrivateKey(AsymmetricKeyParameter key, ECDomainParameters parameters) {
		return new ECPrivateKeyParameters(((ECPrivateKeyParameters) key).getD(), parameters);
	}
	
	/**	
	 * 	生成私钥
	 * 	
	 * 	@author Pan
	 * 	@param 	keyPair		密钥对
	 * 	@param 	parameters	椭圆曲线参数
	 * 	@return	ECPrivateKeyParameters
	 */
	public static ECPrivateKeyParameters generatePrivateKey(AsymmetricCipherKeyPair keyPair, ECDomainParameters parameters) {
		return generatePrivateKey(keyPair.getPrivate(), parameters);
	}
	
	/**	
	 * 	生成私钥
	 * 	
	 * 	@author Pan
	 * 	@param 	privateKey	私钥
	 * 	@param 	parameters	椭圆曲线参数
	 * 	@return	ECPrivateKeyParameters
	 */
	public static ECPrivateKeyParameters generatePrivateKey(byte[] privateKey, ECDomainParameters parameters) {
		try {
			//	默认D值解析
			if (ValidParam.isNotNull(parameters)) {
				return new ECPrivateKeyParameters(new BigInteger(1, privateKey), parameters);
			}
		} catch (Exception e) {
			//	do nothing
		}
		
		//	X.509解析
		try {
			PrivateKeyInfo privateKeyInfo = PrivateKeyInfo.getInstance(privateKey);
			return (ECPrivateKeyParameters) PrivateKeyFactory.createKey(privateKeyInfo);
		} catch (Exception e) {
			try {
				//	OpenSSH解析
				//	OpenSSHPrivateKeySpec pKeySpec = new OpenSSHPrivateKeySpec(encodedKey);
				return (ECPrivateKeyParameters) OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(privateKey);
			} catch (Exception e2) {
				throw new InitPublicKeyException(e2.getMessage(), e2);
			}
			
		}
	}
	
	/**	
	 * 	生成私钥
	 * 	
	 * 	@author Pan
	 * 	@param 	privateKey	私钥
	 * 	@return	ECPrivateKeyParameters
	 */
	public static ECPrivateKeyParameters generatePrivateKey(PrivateKey privateKey) {
		try {
			return (ECPrivateKeyParameters) ECUtil.generatePrivateKeyParameter(privateKey);
		} catch (Exception e) {
			throw new InitPrivateKeyException(e.getMessage(), e);
		}
	}
	
	/**
	 * 	将key转换成byte[]
	 * 	
	 * 	@author Pan
	 * 	@param 	key	公钥/私钥
	 * 	@return	byte[]
	 */
	public static byte[] encodeToBytes(AsymmetricKeyParameter key) {
		try {
			if (key.isPrivate()) {
				return PrivateKeyInfoFactory.createPrivateKeyInfo(key).getEncoded();
			}
			return SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(key).getEncoded();
		} catch (Exception e) {
			throw new IllegalArgumentException(e.getMessage(), e);
		}
	}
	
	/**
	 * 	将key编码成十六进制
	 * 	
	 * 	@author Pan
	 * 	@param 	key	公钥/私钥
	 * 	@return	byte[]
	 */
	public static String encodeToHex(AsymmetricKeyParameter key) {
		return HexUtils.encode(encodeToBytes(key));
	}
	
	/**
	 * 	将key编码成Base64字符串
	 * 	
	 * 	@author Pan
	 * 	@param 	key	公钥/私钥
	 * 	@return	byte[]
	 */
	public static byte[] encodeToBase64(AsymmetricKeyParameter key) {
		return Base64Utils.encode(encodeToBytes(key));
	}
	
	/**
	 * 	将key编码成Base64
	 * 	
	 * 	@author Pan
	 * 	@param 	key	公钥/私钥
	 * 	@return	String
	 */
	public static String encodeToBase64Str(AsymmetricKeyParameter key) {
		return Base64Utils.encodeToStr(encodeToBytes(key));
	}
}
